/*! 
通知各个工作线程退出的结构

Shutdown的工作机制比较有意思，充分利用了tokio::sync::broadcast的特性。
- 多生产者、多消费者广播队列，所有消费者都可以看到每个发送的值。
- let mut rx2 = tx.subscribe(); 可以随时生成新的订阅者；
- 当所有生产者关闭时，各接收者调用recv将返回RecvError:：Closed，所以即使不发退出消息，只要tx关闭，各rx自然就收到了Colsed的消息。
- Shutdown还提供了查询的机制（这个也很重要，也是不直接使用signal::ctrl_c()的原因）
*/
use tokio::sync::broadcast;

#[derive(Debug)]
pub(crate) struct Shutdown {
    shutdown: bool,
    notify: broadcast::Receiver<()>,
}

impl Shutdown {
    pub(crate) fn new(notify: broadcast::Receiver<()>) -> Shutdown {
        Shutdown {
            shutdown: false,
            notify,
        }
    }

    pub(crate) fn is_shutdown(&self) -> bool {
        self.shutdown
    }

    pub(crate) async fn recv(&mut self) {
        if self.shutdown {
            return;
        }
        // 当主服务退出时，删除发件人句柄，各个子监听线程调用recv将返回RecvError:：Closed，同样被视为shutdown！
        let _ = self.notify.recv().await;
        // Remember that the signal has been received.
        self.shutdown = true;
    }
}
